# -*- coding: utf-8 -*-
"""
Module Description: 处理dal具体操作的主控制器
"""
from operator import itemgetter
from datetime import datetime, date
try:
    import simplejson as json
except ImportError:
    import json
from framework.dal.orm import get_db_name
from framework.dal.orm.remote_call.call_adapter import *
from framework.dal.orm.orm_expection import ORMException, TransactionsInsertException
from framework.dal.transaction import transactin_context_storage, TransactionPropagation
from framework.firefly_dc import runtime_logger as log

# 加速访问
get_db_name = get_db_name


# TODO: 这几个Aggregate最好合并到一个aggregate文件中
class AggregateCount(object):
    """count聚合函数"""
    @staticmethod
    def get_column_name():
        return 'count(*)'


class AggregateMin(object):
    """min聚合函数"""
    @staticmethod
    def get_column_name(field):
        return 'min({})'.format(field)


class AggregateMax(object):
    """max聚合函数"""
    @staticmethod
    def get_column_name(field):
        return 'max({})'.format(field)


def valid_date(date_str):
    """
    尝试进行时间日期格式的数据转换
    :param date_str:
    :return:
    """

    if date_str:
        try:
            if '-' in date_str and ':' in date_str:
                # 处理 2017-06-22 12:00:22型时间
                tmp = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S")
                return datetime(tmp.year, tmp.month, tmp.day, tmp.hour, tmp.minute, tmp.second)
            elif '-' in date_str and ':' not in date_str:
                # 处理 2017-06-22型时间
                tmp = datetime.strptime(date_str, '%Y-%m-%d').date()
                return datetime(tmp.year, tmp.month, tmp.day).date()
            else:
                # 处理 12:00:22型时间
                tmp = datetime.strptime(date_str, '%H:%M:%S').time()
                return tmp
        except:
            # 处理不成时间,返回原来结果
            return date_str
    else:
        return date_str


def parse_datetime_field_value_to_string_in_place(data_list):
    """
    将插入的字典列表中值为datetime/date的字段转为字符串
    :param data_list:
    :return:
    """
    # 找到时间日期格式的字段, 将其转换为string
    # [(idx, field_name)]
    data_field_tag = []
    for idx, data in enumerate(data_list):
        for field_name, val in data.iteritems():
            if isinstance(val, datetime) or isinstance(val, date):
                data_field_tag.append((idx, field_name))

    for idx, field_name in data_field_tag:
        val = data_list[idx][field_name]
        if isinstance(val, datetime):
            data_list[idx][field_name] = val.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(val, date):
            data_list[idx][field_name] = val.strftime('%Y-%m-%d')


def check_now_is_in_transaction_stack():
    """
    判断当前是否处于正常的事务模式中
    :return:
    """
    return transactin_context_storage.ctx and not transactin_context_storage.ctx.is_tx_stack_empty() \
           and transactin_context_storage.ctx.cur_tx.propagation != TransactionPropagation.NOT_SUPPORTED


class CompatibilityUtility(object):
    """
    兼容性工具类
    """

    @staticmethod
    def parse_order_list_to_string(order_list):
        """
        编码排序字段列表为字符串格式
        :param order_list: ['Id', '-SecId']
        :return: 'Id__ASC,SecId__DESC'
        """
        if not order_list:
            return

        order_fields = list()
        for field in order_list:
            if field[0] == '-':
                field = field[1:] + '__DESC'
            else:
                field += '__ASC'
            order_fields.append(field)
        return ','.join(order_fields)


def model_info(db, model):
    db_name = db['db']
    trace_id = db['trace_id']
    trans_dict = db.get('transaction', {})
    model_name = model.__class__.__name__
    return db_name, model_name, trace_id, trans_dict


class ORMController(object):

    @staticmethod
    def insert(model):
        db_name = get_db_name()
        pks = model.__class__.get_primary_keys()
        model_name = model.__class__.__name__

        values = [model.for_storage_dict()]

        # 如果trace_id有事务对象,并且事务对象的_no_tx属性不是True,则放入事务对象中，否则直接执行
        if check_now_is_in_transaction_stack():
            d = dict()
            d['orm'] = model_name
            d['pk'] = pks
            d['action'] = 'insert'
            d['body'] = {"values": values}
            # 用于判断这个操作是不是全主键操作
            d['is_all_key'] = True
            transactin_context_storage.ctx.cur_tx.transaction_append(d)

            # 需要给create方法返回结果,create得不到对象
            return True

        else:
            insert_result = insert_model(db_name, model.__class__, values)
            return int(insert_result) == 1 if insert_result else insert_result

    @staticmethod
    def delete(model):
        db_name = get_db_name()
        pks = model.__class__.get_primary_keys()
        model_name = model.__class__.__name__

        conditions = dict()
        for pk in pks:
            val = model.attributes_dict[pk]
            conditions[pk + '__eq'] = val

        if check_now_is_in_transaction_stack():
            d = dict()
            d['orm'] = model_name
            d['pk'] = pks
            d['action'] = 'delete'
            conditions['operator'] = 'AND'
            d['body'] = conditions
            # 用于判断这个操作是不是全主键操作
            d['is_all_key'] = True
            transactin_context_storage.ctx.cur_tx.transaction_append(d)

        else:
            if conditions.values():
                delete_result = delete_model(db_name, model.__class__, conditions)
                return int(delete_result) == 1
            else:
                raise ORMException("no available conditions")

    @staticmethod
    def delete_by_conditions(mdl_cls, conditions, operator='AND'):
        db_name = get_db_name()
        pks = mdl_cls.get_primary_keys()
        model_name = mdl_cls.__name__

        if len(pks) == 0:
            raise ORMException("no primary keys")
        if check_now_is_in_transaction_stack():
            d = dict()
            d['orm'] = model_name
            d['pk'] = pks
            d['action'] = 'delete'
            d['body'] = conditions
            # 用于判断这个操作是不是全主键操作
            model_pks_eq = mdl_cls.get_all_eq_primary_keys()
            # 判断model_pks_eq的所有主键是否都在conditions中,如果有
            if isinstance(conditions, dict) and set(model_pks_eq).issubset(set(conditions.keys())):
                d['is_all_key'] = True
            else:
                d['is_all_key'] = False
            transactin_context_storage.ctx.cur_tx.transaction_append(d)

        else:
            delete_result = delete_model(db_name, mdl_cls, conditions, operator)
            return int(delete_result) > 0

    @staticmethod
    def update(model):
        db_name = get_db_name()
        pks = model.__class__.get_primary_keys()
        model_name = model.__class__.__name__

        conditions = dict()
        if pks:
            for pk in pks:
                val = model.attributes_dict[pk]
                conditions[pk + '__eq'] = val
        else:
            raise ORMException("no primary keys")

        # values = model.for_storage_dict()
        values = model.for_update_dict()
        if not values:
            # 判断更新操作的字典update_temp_dict中没有值,则返回操作成功
            return True

        """{"orm": "对象名", "pk": "主键名", "action": "update", "body": {"values": {"字段名": 字段值, ...},
            "conditions": {"字段名__运算符": 字段值, ..., "operator": "AND[OR]"}},"""
        if check_now_is_in_transaction_stack():
            t_action_update_value = model.for_storage_dict()
            t_action_update_value.update(values)
            d = dict()
            d['orm'] = model_name
            d['pk'] = pks
            d['action'] = 'update'
            # conditions['operator'] = 'AND'
            d['body'] = {'values': values, 'conditions': conditions, 'operator': 'AND'}
            # 用于判断这个操作是不是全主键操作
            d['is_all_key'] = True
            transactin_context_storage.ctx.cur_tx.transaction_append(d, t_action_update_value)
            model.clear_update_dict()

        else:
            update_result = update_model(db_name, model_name, pks, values, conditions)
            model.clear_update_dict()
            return int(update_result) == 1

    @staticmethod
    def update_by_conditions(mdl_cls, conditions, values, operator='AND'):
        db_name = get_db_name()
        pks = mdl_cls.get_primary_keys()
        model_name = mdl_cls.__name__

        if len(pks) == 0:
            raise ORMException("no primary keys")

        if not values:
            raise ORMException("no need up data value")

        if check_now_is_in_transaction_stack():
            d = dict()
            d['orm'] = model_name
            d['pk'] = pks
            d['action'] = 'update'
            conditions['operator'] = operator
            d['body'] = {'values': values, 'conditions': conditions}
            # 用于判断这个操作是不是全主键操作
            model_pks_eq = mdl_cls.get_all_eq_primary_keys()
            # 判断model_pks_eq的所有主键是否都在conditions中,如果有
            if isinstance(conditions, dict) and set(model_pks_eq).issubset(set(conditions.keys())):
                d['is_all_key'] = True
            else:
                d['is_all_key'] = False
            transactin_context_storage.ctx.cur_tx.transaction_append(d)

        else:
            update_result = update_model(db_name, model_name, pks, values, conditions, operator)
            return int(update_result) > 0

    @staticmethod
    def count(mdl_cls, conditions):
        """
        从指定表查询指定条件的记录数
        :param mdl_cls:
        :param conditions: filter查询条件列表
        :return: int
        """
        db_name = get_db_name()
        select_result = select_count(db_name, mdl_cls, conditions=conditions)
        return 0 if not select_result else select_result[0].get(AggregateCount.get_column_name(), 0)

    @staticmethod
    def min(mdl_cls, field_name, conditions):
        """
        从指定表查询指定条件的最小值
        :param mdl_cls:
        :param field_name: 字段名
        :param conditions: filter查询条件列表
        :return: int
        """
        db_name = get_db_name()
        select_result = select_min(db_name, mdl_cls, field_name=field_name, conditions=conditions)
        min_val = None if not select_result else select_result[0].get(AggregateMin.get_column_name(field_name))
        return valid_date(min_val)

    @staticmethod
    def max(mdl_cls, field_name, conditions):
        """
        从指定表查询指定条件的最大值
        :param mdl_cls:
        :param field_name: 字段名
        :param conditions: filter查询条件列表
        :return: int
        """
        db_name = get_db_name()
        select_result = select_max(db_name, mdl_cls, field_name=field_name, conditions=conditions)
        max_val = None if not select_result else select_result[0].get(AggregateMax.get_column_name(field_name))
        return valid_date(max_val)

    @staticmethod
    def select_model(mdl_cls, conditions, columns=None, operator="AND", order=None, limit=None, offset=0):
        db_name = get_db_name()
        pks = mdl_cls.get_primary_keys()
        try:
            select_result = []
            flag = True

            if check_now_is_in_transaction_stack():
                # 事务环境下,如果查询到本地的记录有insert或者delete,则不执行查询,使用本地记录,如果没找到在使用查询
                # 需要flag判断是否要执行查询
                select_result, flag = DataProcess.search_local_data(mdl_cls, db_name, conditions)

            if flag:
                # 访问db进行查询
                select_result = select_model(
                    db_name=db_name,
                    model_name=mdl_cls.__name__,
                    pks=pks,
                    conditions=conditions,
                    columns=columns,
                    operator=operator,
                    order=CompatibilityUtility.parse_order_list_to_string(order),
                    limit=limit,
                    offset=offset
                )
                select_result = DataProcess.search_data_process(mdl_cls, select_result, db_name, conditions,
                                                                columns, order, limit)

            return ORMController._create_model_list(mdl_cls, select_result, readonly=bool(columns))
        except ValueError as e:
            raise ORMException(e)

    @staticmethod
    def commit_transaction(trans_obj, work):
        try:
            res = transaction_model(trans_obj, work)
            return int(res) > 0
        except ValueError as e:
            raise ORMException(e)

    @staticmethod
    def _create_model_list(model_cls, res, readonly=False):
        """
        根据查询结果, 创建结果集并返回
        :param model_cls: dal.orm模型类
        :param res: 从数据源查到的数据
        :param readonly: 是否只读model
        :return:
        """
        model_list = list()
        for dic in res:
            model = model_cls(**dic)
            model._isnew = False
            model._readonly = readonly
            model._update_temp_dict = dict()
            model_list.append(model)
        return model_list

    @staticmethod
    def execute_sql(sql, params_list=None):
        """
        直接执行sql
        :param sql:
        :param params_list:
        :return: 对于查询,返回字典列表;对于CUD,返回空列表
        """
        db_name = get_db_name()

        if params_list:
            sql = sql % params_list

        execute_result = query_sql(db_name, sql)

        model_list = list()
        if execute_result and isinstance(execute_result, list):
            for dic in execute_result:
                for name, value in dic.items():
                    value = valid_date(value)
                    dic[name] = value
                model_list.append(dic)
        return model_list

    @staticmethod
    def insert_many(mdl_cls, obj_list):
        """
        批量插入
        :param mdl_cls:
        :param obj_list:
        :return:
        """
        db_name = get_db_name()
        pks = mdl_cls.get_primary_keys()

        parse_datetime_field_value_to_string_in_place(obj_list)

        if check_now_is_in_transaction_stack():
            d = dict()
            d['orm'] = mdl_cls.__name__
            d['pk'] = pks
            d['action'] = 'insert'
            d['body'] = {"values": obj_list}
            # 默认插入的数据有全主键信息
            d['is_all_key'] = True
            transactin_context_storage.ctx.cur_tx.transaction_append(d)

        else:
            insert_result = insert_model(db_name, mdl_cls, obj_list)
            return int(insert_result) > 0 if insert_result else insert_result


class FuncChoose(object):
    """这个类用来通过传入的条件# 操作运算符：eq: =, ne: !=, lt: <, lte: <=, gt: >, gte: >=
    所需要的运行方法
    用lambda表达式，可读性差,所以建了这个类
    """
    @staticmethod
    def eq_func(key, value, action, k_type, *args, **kwargs):
        if action.get(key) is None or value is None:
            return False
        elif k_type == "int":
            return int(action.get(key)) == int(value)
        else:
            return action.get(key) == value

    @staticmethod
    def ne_func(key, value, action, k_type, *args, **kwargs):
        if action.get(key) is None or value is None:
            return False
        elif k_type == "int":
            return int(action.get(key)) != int(value)
        else:
            return action.get(key) != value

    @staticmethod
    def lt_func(key, value, action, k_type, *args, **kwargs):
        if action.get(key) is None or value is None:
            return False
        elif k_type == "int":
            return int(action.get(key)) < int(value)
        else:
            return action.get(key) < value

    @staticmethod
    def lte_func(key, value, action, k_type, *args, **kwargs):
        if action.get(key) is None or value is None:
            return False
        elif k_type == "int":
            return int(action.get(key)) <= int(value)
        else:
            return action.get(key) <= value

    @staticmethod
    def gt_func(key, value, action, k_type, *args, **kwargs):
        if action.get(key) is None or value is None:
            return False
        elif k_type == "int":
            return int(action.get(key)) > int(value)
        else:
            return action.get(key) > value

    @staticmethod
    def gte_func(key, value, action, k_type, *args, **kwargs):
        if action.get(key) is None or value is None:
            return False
        elif k_type == "int":
            return int(action.get(key)) >= int(value)
        else:
            return action.get(key) >= value

    @staticmethod
    def like_func(key, value, action, k_type, *args, **kwargs):
        import re
        if action.get(key) is None or value is None:
            return False
        else:
            if "%" not in value:
                user_input = value + ".*?"
            else:
                # 开头^， 结尾$
                if value[0] != "%":
                    value = "^" + value
                if value[-1] != "%":
                    value += "$"
                user_input = value.replace("%", ".*?")
            regex = re.compile(user_input)  # Compiles a regex.
            if regex.search(str(action.get(key))):
                return True
            else:
                return False

    @staticmethod
    def is_func(key, value, action, k_type, *args, **kwargs):
        if value == str(None):
            value = None
        if action.get(key) is value:
            return True
        else:
            return False

    @staticmethod
    def isnot_func(key, value, action, k_type, *args, **kwargs):
        if value == str(None):
            value = None
        if action.get(key) is not value:
            return True
        else:
            return False

    @staticmethod
    def in_func(key, value, action, k_type, *args, **kwargs):
        if key not in action or not value:
            return False
        else:
            # 使用eval将 字符串列表字符串 转为 字符串列表, 需要寻找新方法
            # "['5a085d0f84', '5a085d0f85']"  -> ['5a085d0f84', '5a085d0f85']
            return action.get(key) in value


class DataProcess(object):
    """用来处理查询结果的类"""
    func_dict = {"eq": FuncChoose.eq_func,
                 "ne": FuncChoose.ne_func,
                 "lt": FuncChoose.lt_func,
                 "lte": FuncChoose.lte_func,
                 "gt": FuncChoose.gt_func,
                 "gte": FuncChoose.gte_func,
                 "like": FuncChoose.like_func,
                 "is": FuncChoose.is_func,
                 "isnot": FuncChoose.isnot_func,
                 "in": FuncChoose.in_func}

    @staticmethod
    def _get_table_action(model_cls, db_name):
        """
        获取当前整个嵌套事务栈中,对某个表的所有主键改动记录
        :param model_cls:
        :param db_name: 数据表名
        :return: dict
        """
        return transactin_context_storage.ctx.tx_change_stack[-1]. \
            get(db_name, {}). \
            get(model_cls.__name__, {})

    @staticmethod
    def search_local_data(model_cls, db_name, s_conditions):
        """
        :return: select_result,返回的结果; flag:用于判断下一步是否需要执行远端查询
        """
        # 用来查询本地的t_action中时候存有需要查询的记录
        t_action_result = list()
        if not s_conditions:
            # 没有条件,是全表查询,需要继续查询远端记录
            return t_action_result, True
        table_action = DataProcess._get_table_action(model_cls, db_name)
        table_pk = DataProcess.get_pk_str(model_cls.get_all_eq_primary_keys(), s_conditions)
        a_result = table_action.get(table_pk, {})
        # 如果有找到有主键事务的操作结果
        if a_result:
            if a_result.get('action') == "insert":
                t_action_result.append(a_result.get("value"))
                return t_action_result, False
            elif a_result.get('action') == "delete":
                t_action_result = []
                return t_action_result, False
        return t_action_result, True

    @staticmethod
    def search_data_process(model_cls, select_result, db_name, s_conditions=None, columns=None, order=None, limit=None):
        """
        用来处理查询数据的方法
        :param model_cls:查询时的model类
        :param select_result:远端返回的查询结果
        :param db_name:
        :param s_conditions:查询时的条件字典
        :param columns:查询时的字段限制
        :param order:查询时的排序限制
        :return:
        """
        if not transactin_context_storage.ctx:
            # 没有这个事务,普通查询
            return select_result

        # 处于事务内, 对结果集进行二次比对,填充结果集↓↓

        # 对带columns查询的特殊判断
        if columns:
            # 如果查询中有columns, 且结果中不包含所有主键字段,不进行操作
            for pk_field in model_cls.get_primary_keys():
                # 若事务内带columns条件且不包含所有主键字段,则查询得不到事务内的更新记录
                if pk_field not in columns:
                    return select_result

        model_pks_eq = model_cls.get_all_eq_primary_keys()
        # 判断model_pks_eq的所有主键是否都在conditions中,如果有
        if isinstance(s_conditions, dict) and set(model_pks_eq).issubset(set(s_conditions.keys())):
            return DataProcess._modify_primary_search_result(model_cls, select_result, db_name, s_conditions)
        else:
            # 这里是没有通过查询条件是全主键的判断
            return DataProcess._modify_filter_search_result(model_cls, select_result, db_name, s_conditions, order, limit)

    @staticmethod
    def _modify_primary_search_result(model_cls, select_result, db_name, s_conditions):
        """
        这个方法用来修改全主键查询的查询结果
        :param model_cls:查询时的model类
        :param select_result:远端返回的查询结果
        :param db_name:
        :param s_conditions:查询时的条件字典
        :return:
        """
        # 两种情况
        # 如果没有数据,寻找是否有插入数据，更新数据
        table_action = DataProcess._get_table_action(model_cls, db_name)
        if not select_result:
            table_pk = DataProcess.get_pk_str(model_cls.get_all_eq_primary_keys(), s_conditions)
            a_result = table_action.get(table_pk, {})
            # 如果有找到有主键事务的操作结果
            if a_result:
                    if a_result.get('action') == "insert":
                        select_result.append(a_result.get("value"))
                    elif a_result.get('action') == "update":
                            # 如果此时res不为空了，既前面有创建对象了
                            if select_result:
                                select_result[0].update(a_result.get("value"))
                            else:
                                select_result.append(a_result.get("value"))
                    elif a_result.get('action') == "delete":
                            # 这个删除操作，符合查询条件,既事务中有删除操作的值符合查询条件,需要删除select_result
                            select_result = []
            return select_result

        elif len(select_result) == 1:
                # 已经查询到数据库有一条主键的数据,那么只查找事务操作中是否有对这条数据的更新操作
            table_pk = DataProcess.get_pk_str(model_cls.get_all_eq_primary_keys(), s_conditions)
            a_result = table_action.get(table_pk, {})
            # 如果有找到有主键事务的操作结果
            if a_result:
                    if a_result.get('action') == "update":
                            # 这个更新操作，符合查询条件,既事务中有更新操作的值符合查询条件,需要修改select_result的值
                            select_result[0].update(a_result.get("value"))
                    elif a_result.get('action') == "delete":
                            # 这个删除操作，符合查询条件,既事务中有删除操作的值符合查询条件,需要删除select_result
                            select_result = []
            return select_result
        else:
            # 不应该走到这里,全主键的查询,却找到了多条记录,可能是sdk这边填写的主键无法找到数据库中的唯一记录
            raise ORMException("primary keys error")

    @staticmethod
    def _modify_filter_search_result(model_cls, select_result, db_name, s_conditions, order, limit):
        """
        这个方法用来修改filter查询的结果,不是全主键查询的类型
        # 如果因为并发原因,导致查询中有记录,而事务中t_action也有插入操作，则报异常
        # t_action更新直接覆盖结果
        # t_action删除直接覆盖结果
        :param model_cls:查询时的model类
        :param select_result:远端返回的查询结果
        :param db_name:
        :param s_conditions:查询时的条件字典
        :return:
        """
        ################################
        # 用本地事务改动结果集更新远端返回的结果集:
        # 1. 已在db中, 且本地也进行插入的, 报错
        # 2. 本地进行了更新, 则更新db记录
        # 3. 本地进行了删除, 则从db结果集中移除
        ################################
        table_action = DataProcess._get_table_action(model_cls, db_name)
        # 本地事务没有修改这张表, 不进行二次比对直接返回
        if not table_action:
            return select_result

        # 被本地事务update了的db结果集pks集合
        updated_by_local_change_pks = []

        temp_select_result = list()
        for idx, db_rcd in enumerate(select_result):
            # 由于遍历过程中删除select_result的数据，会导致遍历提前结束，更新操作也会有误
            table_pk = DataProcess.get_pk_str(model_cls.get_primary_keys(), db_rcd)
            a_result = table_action.get(table_pk, {})
            # 如果one_res找到了在事务t_action中有操作记录
            if a_result:
                if a_result.get('action') == "insert":
                    # 如果因为并发原因,导致db返回中有记录,而事务中t_action也有插入相同主键的操作，则报异常
                    raise TransactionsInsertException("Error 1062: Duplicate entry "
                                                      + table_pk + "  for key 'PRIMARY'")
                elif a_result.get('action') == "update":
                    # 直接更新db结果集
                    select_result[idx].update(a_result.get("value"))
                    temp_select_result.append(select_result[idx])

                    updated_by_local_change_pks.append(table_pk)
                elif a_result.get('action') == "delete":
                    # 从结果集中舍弃已在本地删除的记录
                    pass
            else:
                temp_select_result.append(db_rcd)

        select_result = temp_select_result

        # 到这里,做完了所有查询结果与t_action中的结果对比,既通过查询结果中的主键与t_action中的主键对比，操作结果

        # 是否执行从t_action中取出符合查询条件的结果,这个主要处理可能t_action中有的记录在数据库中不存在
        # 处理掉远端返回的结果,不在查询条件中的记录
        select_result = DataProcess._modify_filter_search_result_by_conditions(model_cls, select_result, db_name, s_conditions,
                                                                               updated_by_local_change_pks)

        if order:
            DataProcess.sort_search_result(select_result, order)

        if limit:
            select_result = select_result[:int(limit)]

        return select_result

    @staticmethod
    def _modify_filter_search_result_by_conditions(model_cls, select_result, db_name, s_conditions,
                                                   updated_by_local_change_pks):
        """
        这个方法用来处理,t_action中的结果还没有提交，导致查询的时候没有查询到记录，在这个方法中，将这些记录加入查询结果
        :param model_cls:查询时的model类
        :param select_result:远端返回的查询结果+本地新增结果
        :param db_name:
        :param s_conditions:查询时的条件字典
        :param updated_by_local_change_pks: 被本地事务update了的db结果集pks集合
        :return:
        """
        result_from_t_action = dict()

        # TODO: select_result在_modify_filter_search_result使用table_action进行了更新, 但没有把本地的insert加入进去
        # TODO: 后续就还需要table_action参与
        table_action = DataProcess._get_table_action(model_cls, db_name)

        # 将select_result[]的每个记录的主键值组合作为key,记录作为value保存到下面这个dict
        select_result_pks_value = dict()
        for a_select in select_result:
            a_select_pk = DataProcess.get_pk_str(model_cls.get_primary_keys(), a_select)
            select_result_pks_value.update({a_select_pk: a_select})

        if not s_conditions:
            # 如果没有条件，那么是全表查询,把所有t_action中的结果加入查询结果
            DataProcess._search_result_from_t_action_all(result_from_t_action, select_result_pks_value, table_action)
        else:
            search_first_condition_records = False
            for conditions_k, conditions_v in s_conditions.iteritems():
                # 从本地事务中筛选符合第一个条件的记录, 后续的本地事务筛选集合继续使用上一次的筛选结果集
                # 得到最终本地符合条件的结果集result_from_t_action
                if not search_first_condition_records:
                    # 第一次查询整个t_action中的结果
                    DataProcess._search_result_from_t_action_by_conditions(model_cls, result_from_t_action, conditions_k,
                                                                           conditions_v, select_result_pks_value,
                                                                           updated_by_local_change_pks, table_action)
                    search_first_condition_records = True
                else:
                    # 后面的条件直接继续筛选result_from_t_action
                    DataProcess._search_result_from_t_action_by_conditions(model_cls, result_from_t_action, conditions_k,
                                                                           conditions_v, select_result_pks_value,
                                                                           updated_by_local_change_pks)

        # 把处理完的temp_list与select_result对比，如果没有在select_result中，则把结果放入select_result中
        # 注意: 这里会使得db返回的结果集乱序掉
        process_select_result = [s_result for s_result in select_result_pks_value.values()]
        process_select_result.extend([r_result for r_result in result_from_t_action.values()])
        return process_select_result

    @staticmethod
    def _search_result_from_t_action_by_conditions(model_cls, result_from_t_action, conditions_k, conditions_v,
                                                   select_result_pks_value, updated_by_local_change_pks, table_action=None):
        """
        这个方法用来处理,找出t_action中的符合条件的结果
        分两步，
        1，如果这个是第一个条件，那么就对比查询条件与table_action中的结果，如果结果的主键值没有在select_list_pk中则将结果放入temp_list中
        2，如果前面有执行过条件了，既temp_list有上一个条件的结果了，那么从temp_list中查找不符合条件的结果，删除掉
        :param model_cls:查询的model类
        :param result_from_t_action:用来保存从t_action中查出的结果
        :param conditions_k:查询条件字典中的key
        :param conditions_v:查询条件字典中的value
        :param select_result_pks_value:从远端返回的结果的pk值和数据组成的字典
        :param updated_by_local_change_pks: 被本地事务update了的db结果集pks集合
        :param table_action:t_action中的所有结果
        :return:
        """
        if table_action is not None:
            # 遍历table_action,符合条件放入temp_list
            for act_pks in table_action:
                flag = DataProcess._cmp_conditions_action(model_cls, conditions_k, conditions_v, table_action[act_pks]["value"])
                # 符合这个查询条件, 且不在db返回的结果中, 则添加到result_from_t_action
                if flag and act_pks not in select_result_pks_value:
                    result_from_t_action.update({act_pks: table_action[act_pks]["value"]})
                # 若不符合这个查询条件, 且在db返回的结果中, 从db返回的结果中删除, 因为在本地已经被修改到不符合条件了
                elif not flag and act_pks in select_result_pks_value:
                    del select_result_pks_value[act_pks]

            # select_result_pks_value已经不只是db返回的结果集了,使用本地的判定规则再对db返回的结果进行一次筛选
            for act_pks in select_result_pks_value.keys():
                # 如果db结果集记录没有被本地事务改动(update), 那么不用进行本地筛选自动通过
                if act_pks not in updated_by_local_change_pks:
                    continue

                flag = DataProcess._cmp_conditions_action(model_cls, conditions_k, conditions_v, select_result_pks_value[act_pks])
                if not flag:
                    del select_result_pks_value[act_pks]

        else:
            # 从temp_list删除与条件kv不符合的结果
            for act_pks in result_from_t_action.keys():
                flag = DataProcess._cmp_conditions_action(model_cls, conditions_k, conditions_v, result_from_t_action[act_pks])
                if not flag:
                    del result_from_t_action[act_pks]

            # 第二个条件之后的条件也要判断select_result_pks_value这个里面的值是否符合条件
            for act_pks in select_result_pks_value.keys():
                # 如果db结果集记录没有被本地事务改动(update), 那么不用进行本地筛选自动通过
                if act_pks not in updated_by_local_change_pks:
                    continue
                flag = DataProcess._cmp_conditions_action(model_cls, conditions_k, conditions_v, select_result_pks_value[act_pks])
                if not flag:
                    del select_result_pks_value[act_pks]

    @staticmethod
    def _search_result_from_t_action_all(result_from_t_action,
                                         select_result_pks_value, table_action):
        """
        这个方法用来处理,查询条件为空时,将所有t_action中的结果放入查询结果中
        :param result_from_t_action:用来保存从t_action中查出的结果
        :param select_result_pks_value:(从远端返回的结果+本地update和insert结果)的pk值和数据组成的字典
        :param table_action:t_action中的所有结果
        :return:
        """
        # 遍历table_action,符合条件放入temp_list
        for act_pks in table_action:
            if act_pks not in select_result_pks_value and table_action[act_pks]["action"] != "delete":
                result_from_t_action.update({act_pks: table_action[act_pks]["value"]})

    @staticmethod
    def _cmp_conditions_action(model_cls, conditions_k, conditions_v, one_action):
        """
        这个方法用来对比传入的条件k,v既（字段__操作符,和值）是否与one_action符合
        如果符合条件返回True，否则返回False
        # 操作运算符：eq: =, ne: !=, lt: <, lte: <=, gt: >, gte: >=, like:模糊匹配, is:是None， isnot：不是None
        :param model_cls:查询的model类
        :param conditions_k:查询条件字典中的key
        :param conditions_v:查询条件字典中的value
        :param one_action:一个t_action中保存的结果
        :return:
        """
        k_list = conditions_k.split("__")
        if len(k_list) == 2:
            # 如果切割的条件完长度不是2，可能哪里错了
            f = DataProcess.choose_func(k_list[1])
            return f(k_list[0], conditions_v, one_action, model_cls.attributes().get(k_list[0]).str_type())
        else:
            return False

    @staticmethod
    def choose_func(condition):
        """
        通过传入的条件选择对应 执行的方法
        :param condition:操作运算符的字符串："eq", "ne", "lt", "lte", "gt", "gte", "like", "is", "isnot"
        :return:
        """
        f = DataProcess.func_dict.get(condition)
        if f:
            return f
        else:
            return lambda *args, **kwargs: False

    @staticmethod
    def get_pk_str(model_pks_list, result_dict, conn_flag="---"):
        """
        这个方法用来通过传入的pk列表跟一个结果字典，取出结果字典的pk值，返回一个字符串
        :param model_pks_list: 主键的列表
        :param result_dict:结果的字典
        :param conn_flag:连接主键结果的符号
        :return: str
        """

        temp_pk_value = list()
        for md_pk in model_pks_list:
            temp_pk_value.append(str(result_dict.get(md_pk)))
        return conn_flag.join(temp_pk_value)

    @staticmethod
    def sort_search_result(wait_sort_list, order_list):
        """
        根据排序字段列表对列表进行排序[in place]
        :param wait_sort_list: 待排列表, [{}, {} ... ]
        :param order_list: 排序字段列表, ["A", "B", "-C"]
        :return:
        """
        # comparers = [(fn, mult), ...]
        comparers = [(itemgetter(col[1:].strip()), -1) if col.startswith('-') else (itemgetter(col.strip()), 1)
                     for col in order_list]

        def comparer(left, right):
            for fn, mult in comparers:
                result = cmp(fn(left), fn(right))
                if result:
                    return mult * result
            else:
                return 0

        wait_sort_list.sort(cmp=comparer)
